/*
* Copyright (c) 2021 Talkweb Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef _TIOT_MQTT_API_H_
#define _TIOT_MQTT_API_H_

#if defined(__cplusplus)
extern "C" {
#endif

#include <stdint.h>

typedef enum {
    TIOT_MQTTRECV_PUB,
    TIOT_MQTTRECV_HEARTBEAT_RESPONSE,
    TIOT_MQTTRECV_SUB_ACK,
    TIOT_MQTTRECV_UNSUB_ACK,
    TIOT_MQTTRECV_PUB_ACK,
    TIOT_MQTTRECV_CON_ACK,
    TIOT_MQTTRECV_DISCONNECT,
} tiot_mqtt_recv_type_t;

typedef enum {
    TIOT_MQTT_VERSION_3_1,
    TIOT_MQTT_VERSION_5_0
} tiot_mqtt_protocol_version;

typedef struct {
    uint16_t len;
    uint8_t  *value;
} mqtt5_property_element_t;

typedef struct {
    mqtt5_property_element_t key;
    mqtt5_property_element_t value;
} mqtt5_property_t;

#define MQTT5_ATTRIBUTE_MAX    (20)

/**
 * @brief MQTT 5.0协议中, 下行的conack报文conack中的属性
 */
typedef struct {
    uint8_t max_qos;
    uint16_t topic_alias_max;
    uint8_t *assigned_clientid;
    uint32_t max_packet_size;
    uint16_t server_receive_max;
    uint8_t wildcard_subscription_available;
    uint8_t subscription_identifier_available;
    uint8_t shared_subscription_available;
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];
} connack_property_t;

/**
 * @brief MQTT 5.0协议中, 上行和下行pub报文中的属性.
 */
typedef struct {
    uint32_t message_expire_interval;
    uint16_t topic_alias;
    mqtt5_property_element_t response_topic;
    mqtt5_property_element_t correlation_data;
    uint32_t subscription_identifier;
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];
} pub_property_t;

/**
 * @brief MQTT 5.0协议中, 上行的connect报文中的属性.
 *
 * @details
 *
 * 传入@ref tiot_mqtt_connect_with_prop 的MQTT报文类型
 */
typedef struct {
    uint16_t topic_alias_max;                               /* topic 别名最大数量 */
    uint16_t client_receive_max;
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];      /* 用户属性 */
} conn_property_t;

/**
 * @brief MQTT 5.0协议中, 上行的disconnect报文中的属性.
 *
 * @details
 *
 * 传入@ref tiot_mqtt_disconnect_with_prop 的MQTT报文类型
 *
 */
typedef struct {
    mqtt5_property_element_t *reason_string;
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];      /* 用户属性 */
} disconn_property_t;

/**
 * @brief MQTT 5.0协议中, 上行的subscribe报文中的属性.
 *
 * @details
 *
 * 传入@ref tiot_mqtt_sub_with_prop 的MQTT报文类型
 *
 */
typedef struct {
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];
} sub_property_t;

typedef struct {
    mqtt5_property_t *user_property[MQTT5_ATTRIBUTE_MAX];
} mtt5_unsub_property_t;


typedef struct {
    tiot_mqtt_recv_type_t type;
    union {
        struct {
            uint8_t qos;
            char *topic;
            uint16_t topic_len;
            uint8_t *payload;
            uint32_t payload_len;
            pub_property_t *pub_prop;  /* pub报文中的属性. MQTT 5.0 特性*/
        } pub;
        struct {
            int32_t res;
            uint8_t max_qos;
            uint16_t packet_id;
        } sub_ack;
        struct {
            uint16_t packet_id;
        } unsub_ack;
        struct {
            uint16_t packet_id;
        } pub_ack;
        struct {
            uint8_t reason_code;
            connack_property_t prop;   /* 建连回复报文中的属性. MQTT 5.0 特性 */
        } con_ack;
        struct {
            uint8_t reason_code;
        } server_disconnect;

    } data;
} tiot_mqtt_recv_t;

typedef void (*tiot_mqtt_recv_ctx_t)(void *ctx, const tiot_mqtt_recv_t *packet, void *userdata);

typedef enum {
    TIOT_MQTT_EVENT_CONNECT,
    TIOT_MQTT_EVENT_RECONNECT,
    TIOT_MQTT_EVENT_DISCONNECT
} tiot_mqtt_event_type_t;

typedef enum {
    TIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT,
    TIOT_MQTTDISCONNEVT_HEARTBEAT_DISCONNECT
} tiot_mqtt_disconnect_event_type_t;

typedef struct {
    tiot_mqtt_event_type_t type;
    union {
        tiot_mqtt_disconnect_event_type_t disconnect;
    } data;
} tiot_mqtt_event_t;


typedef void (*tiot_mqtt_event_ctx_t)(void *ctx, const tiot_mqtt_event_t *event, void *userdata);

typedef struct {
    char *topic;
    tiot_mqtt_recv_ctx_t ctx;
    void *userdata;
} tiot_mqtt_topic_map_t;

void   *tiot_mqtt_init(void);
int32_t tiot_mqtt_deinit(void **ctx);
int32_t tiot_mqtt_connect(void *ctx);
int32_t tiot_mqtt_disconnect(void *ctx);
int32_t tiot_mqtt_heartbeat(void *ctx);
int32_t tiot_mqtt_process(void *ctx);
int32_t tiot_mqtt_pub(void *ctx, char *topic, uint8_t *payload, uint32_t payload_len, uint8_t qos);
int32_t tiot_mqtt_pub_with_method(void *ctx, char *topic, uint8_t *payload, uint32_t payload_len, uint8_t qos, const uint8_t *pub_method);
int32_t tiot_mqtt_sub(void *ctx_addr, char *topic, tiot_mqtt_recv_ctx_t ctx, uint8_t qos, void *userdata);
int32_t tiot_mqtt_sub_recv_data(void *ctx, char *msgdata, char **enddata);
int32_t tiot_mqtt_sub_recv_head(void *ctx, char *msgdata, char **enddata);
int32_t tiot_mqtt_unsub(void *ctx, char *topic);
int32_t tiot_mqtt_recv(void *ctx);
int32_t tiot_mqtt_connect_with_prop(void *ctx, conn_property_t *conn_prop);
int32_t tiot_mqtt_sub_with_prop(void *ctx_addr, char *topic, tiot_mqtt_recv_ctx_t ctx, uint8_t qos,
                                void *userdata, sub_property_t *sub_prop);
int32_t tiot_mqtt_unsub_with_prop(void *ctx, char *topic, mtt5_unsub_property_t *unsub_prop);

#if defined(__cplusplus)
}
#endif

#endif

